package com.xscha.tableforge.utils;

import com.xscha.tableforge.constants.DateFormatConstants;
import com.xscha.tableforge.constants.FieldType;
import com.xscha.tableforge.constants.SelectOptionConstants;
import com.xscha.tableforge.constants.SqlTypeConstants;
import com.xscha.soyue.common.core.utils.JsonUtils;
import com.xscha.tableforge.model.dto.FieldMetaDto;
import org.jooq.DataType;
import org.jooq.impl.SQLDataType;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 实体类字段工具类，用于处理实体类字段名与数据库列名的映射
 */
public class EntityFieldUtil {
    
    private static final Map<String, Map<String, String>> ENTITY_FIELD_MAP = new HashMap<>();
    
    /**
     * 获取实体类字段名对应的数据库列名
     * @param entityClass 实体类
     * @param fieldName Java字段名（驼峰命名）
     * @return 数据库列名（下划线命名）
     */
    public static String getColumnName(Class<?> entityClass, String fieldName) {
        if (fieldName == null) {
            return null;
        }
        
        // 获取或创建实体类的字段映射
        Map<String, String> fieldMap = ENTITY_FIELD_MAP.computeIfAbsent(
            entityClass.getName(), k -> createFieldMap(entityClass));
        
        // 返回映射的列名，如果没有映射则返回原字段名
        return fieldMap.getOrDefault(fieldName, fieldName);
    }
    
    /**
     * 创建实体类的字段映射
     */
    private static Map<String, String> createFieldMap(Class<?> entityClass) {
        Map<String, String> fieldMap = new HashMap<>();
        Field[] fields = entityClass.getDeclaredFields();
        
        for (Field field : fields) {
            String fieldName = field.getName();
            String columnName = camelToUnderscore(fieldName);
            fieldMap.put(fieldName, columnName);
        }
        
        return fieldMap;
    }
    
    /**
     * 将驼峰命名转换为下划线命名
     */
    public static String camelToUnderscore(String camel) {
        return camel.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
    }

	/**
	 * 将下划线命名转换为驼峰命名
	 */
	public static String underscoreToCamel(String underscore) {
		if (underscore == null || underscore.isEmpty()) {
			return underscore;
		}

		// 将下划线后的字母转为大写
		Pattern pattern = Pattern.compile("_([a-z])");
		Matcher matcher = pattern.matcher(underscore.toLowerCase());
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
		}
		matcher.appendTail(sb);

		return sb.toString();
	}


    /**
     * 将JSON字符串转换为options Map对象
     *
     * @param jsonString JSON字符串
     * @return Map形式的options
     */
    public static Map<String, Object> convertJsonToOptions(String jsonString) {
        if (jsonString == null || jsonString.isEmpty()) {
            return null;
        }
        try {
			return JsonUtils.toMap(jsonString);
        } catch (Exception e) {
            throw new RuntimeException("解析JSON为options失败", e);
        }
    }

	/**
	 * 将前端字段类型映射为数据库字段类型
	 * @param type 前端字段类型
	 * @return 数据库字段类型
	 */
	public static String mapTypeToDbFieldType(String type) {
		FieldType fieldType = FieldType.fromCode(type);
		if (fieldType == null) {
			return "TEXT"; // 默认类型
		}

		// 使用SqlTypeConstants获取SQL类型
		return SqlTypeConstants.getSqlType(fieldType.getCode(), null);
	}

	/**
	 * 将数据库字段类型转换为jOOQ的DataType
	 */
	public static DataType<?> getJooqDataType(String dbFieldType) {
		if (dbFieldType == null) {
			return SQLDataType.VARCHAR(255);
		}

		switch (dbFieldType.toLowerCase()) {
			case "varchar":
				return SQLDataType.VARCHAR(255);
			case "text":
				return SQLDataType.CLOB;
			case "int":
			case "integer":
				return SQLDataType.INTEGER;
			case "bigint":
				return SQLDataType.BIGINT;
			case "decimal":
				return SQLDataType.DECIMAL(10, 2);
			case "float":
				return SQLDataType.FLOAT;
			case "double":
				return SQLDataType.DOUBLE;
			case "boolean":
				return SQLDataType.BOOLEAN;
			case "date":
				return SQLDataType.DATE;
			case "time":
				return SQLDataType.TIME;
			case "timestamp":
			case "timestamp with time zone":
				return SQLDataType.TIMESTAMP;
			case "jsonb":
				return SQLDataType.JSONB;
			case "json":
				return SQLDataType.JSON;
			default:
				return SQLDataType.VARCHAR(255);
		}
	}

	/**
	 * 处理字段选项
	 */
	public static String processFieldOptions(FieldMetaDto fieldMetaDto) {
		// 如果已经有配置信息，直接返回
		if (fieldMetaDto.getOptions() != null && !fieldMetaDto.getOptions().isEmpty()) {
			return JsonUtils.toJsonString(fieldMetaDto.getOptions());
		}

		// 根据字段类型创建默认配置
		switch (fieldMetaDto.getType().toUpperCase()) {
			case "NUMBER":
				Map<String, Object> numberConfig = new HashMap<>();
				numberConfig.put("type", "decimal");
				numberConfig.put("precision", 2);
				return JsonUtils.toJsonString(numberConfig);

			case "DATE":
				Map<String, Object> dateConfig = new HashMap<>();
				dateConfig.put("format", DateFormatConstants.DEFAULT_DATE_FORMAT);
				dateConfig.put("timeZone", DateFormatConstants.DEFAULT_TIMEZONE);
				dateConfig.put("availableFormats", DateFormatConstants.getDateFormats());
				dateConfig.put("availableTimeZones", DateFormatConstants.getTimeZones());
				return JsonUtils.toJsonString(dateConfig);
			case "DATETIME":
				Map<String, Object> datetimeConfig = new HashMap<>();
				datetimeConfig.put("format", DateFormatConstants.DEFAULT_DATETIME_FORMAT);
				datetimeConfig.put("timeZone", DateFormatConstants.DEFAULT_TIMEZONE);
				datetimeConfig.put("availableFormats", DateFormatConstants.getDateTimeFormats());
				datetimeConfig.put("availableTimeZones", DateFormatConstants.getTimeZones());
				return JsonUtils.toJsonString(datetimeConfig);
			case "TIME":
				Map<String, Object> timeConfig = new HashMap<>();
				timeConfig.put("format", DateFormatConstants.DEFAULT_TIME_FORMAT);
				timeConfig.put("availableFormats", DateFormatConstants.getTimeFormats());
				return JsonUtils.toJsonString(timeConfig);

			case "SINGLE_SELECT":
				return JsonUtils.toJsonString(SelectOptionConstants.getSingleSelectConfig());

			case "MULTI_SELECT":
				return JsonUtils.toJsonString(SelectOptionConstants.getMultiSelectConfig());

			default:
				return JsonUtils.toJsonString(fieldMetaDto.getOptions());
		}
	}
}